package com.clstu.queue;

import java.util.Scanner;

/**
 * 演示基于数组 的环形队列(可以反复使用)
 */
public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        //写一个例子测试是否写对
        //创建一个数组队列
        CircleArrayQueue queue = new CircleArrayQueue(5);
        char key = ' ';//接受键盘输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop) {
            //打印菜单
            System.out.println("\n=======数组环形队列测试=======");
            System.out.println("s(show)     :显示队列");
            System.out.println("a(add)      :添加数据");
            System.out.println("g(getQueue) :从队列取出数据");
            System.out.println("h(head)     :显示队列第一个数据");
            System.out.println("e(exit)     :退出程序");
            System.out.print("请输入:");
            key = scanner.next().charAt(0);
            switch (key) {
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.print("请输入数据:");
                    int data = scanner.nextInt();
                    queue.add(data);
                    break;
                case 'g':
                    try {
                        System.out.println("取出数据:"+queue.getQueue());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'h':
                    try {
                        System.out.println("队列头:"+queue.head());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'e':
                    loop = false;
                    break;
            }
        }
        System.out.println("程序退出~~");
    }
}
/**
 * 写一个环形的数组队列类(front,rear都与普通队列不一样,判断条件也不一样,需要注意)
 */
class CircleArrayQueue{
    private int maxSize;//队列最大长度,(环形队列)能保存的最大数据个数是maxSize-1
    private int front;//头位置 0开始
    private int rear;//尾位置 0开始
    private int[] arr;//数组,用于存放数据,模拟队列

    //构造器,创建队列
    public CircleArrayQueue(int maxSize1){
        maxSize = maxSize1;
        arr = new int[maxSize];
        front = 0;//队列头部,指向第一个数据
        rear = 0;//指向尾部,指向的就是最后一个数据的后一个位置(不是指向最后一个数据!!!!),约定在最后预留一个位置空出来不使用
    }

    //编写方法判断是否位空
    public boolean isEmpty(){
        return front==rear;
    }

    //编写方法判断是否满(环形队列会在最后预留一个位置不使用,如果不预留的话会导致判断是否满时计算起来很麻烦)
    public boolean isFull(){
        return (rear+1) % maxSize == front;
    }

    //编写方法添加数据
    public void add(int data){
        //先判断队列是否满了
        if(isFull()) {
            System.out.println("队列满,不能加入数据了");
            return;
        }
        //加入数据,加入到最后一个数据
        arr[rear]=data;//先在尾部加入数据(因为rear指向的时最后一个数据的后一个位置)
        rear=(rear+1) % maxSize;//后移取模
    }

    //编写方法取出数据
    public int getQueue(){
        //先判断队列是否空
        if(isEmpty()){
            //直接抛出自定义异常
            throw new RuntimeException("队列空,不能取出数据");//抛出异常就可以不加return 了,会自动终止调用
        }
        //拿出数据,拿出第一个数据
        int val = arr[front];//先取出数据(因为front指向的就是第一个数据)
        front = (front+1) % maxSize;//后移取模
        return val;
    }

    //编写方法返回第一个数据
    public int head(){
        //先判断是否空
        if(isEmpty()){
            //直接抛出自定义异常
            throw new RuntimeException("队列空,没有数据");//抛出异常就可以不加return 了,会自动终止调用
        }
        //front就是是第一的数据的位置
        return arr[front % maxSize];
    }

    //编写方法显示所有的队列数据
    public void showQueue(){
        //先判断是否空
        if(isEmpty()){
            System.out.println("队列空,无数据");
            return;
        }
        //显示队列所有数据
        for (int i = front; i < (rear>front?rear:rear+maxSize); i++) {
            System.out.println(arr[i % maxSize]);
        }
    }

}